#include <iostream>
#include "log.hpp"
#include <cerrno>
#include <unistd.h>
#include <cstdlib>
#include <memory>
#include <cstring>
#include "thread.hpp"

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>

uint16_t serverport;
std::string serverip;

static void usage(const std::string &errname)
{
    std::cout << errname << " ServerIP ServrtPORT " << strerror(errno) << std::endl;
}

static void *udpSend(void *args) // 进行发送数据
{
    int sock = *(int *)(((ThreadData *)args)->args_);
    struct sockaddr_in temp;
    memset(&temp, 0, sizeof temp);
    temp.sin_family = AF_INET;
    temp.sin_addr.s_addr = inet_addr(serverip.c_str());
    temp.sin_port = serverport;
    socklen_t len = sizeof(temp);
    while (true)
    {
        std::string str;
        std::cerr << "请输入要发送的消息:";
        getline(std::cin, str);
        if (str == "quit")
            break;
        ssize_t s = sendto(sock, str.c_str(), str.size(), 0, (struct sockaddr *)&temp, len);
        // logMessage(NORMAL, "client sender succees :");
    }
    return nullptr;
}

static void *udpRecv(void *args) // 进行接收提取数据
{
    int sock = *(int *)(((ThreadData *)args)->args_);
    char buffer[1024];

    while (true)
    {
        memset(buffer, 0, sizeof(buffer));
        struct sockaddr_in temp;
        memset(&temp, 0, sizeof(temp));
        socklen_t len = sizeof(temp);
        ssize_t s = recvfrom(sock, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&temp, &len);
        if (s > 0)
        {
            buffer[s] = 0;
            uint16_t sendport = ntohs(temp.sin_port);
            std::string sendip = inet_ntoa(temp.sin_addr);
            std::cout << sendip << "-" << sendport << " " << buffer << std::endl;
            // logMessage(NORMAL, "client recver succees :");
        }
    }
}

int main(int argc, char *argv[])
{
    // 服务端写好了，开始写我们的客户端！客户端应该如何使用呢？我们是不是要让客户端知道我们服务端的IP地址和端口号然后让它们来给我们发送消息啊？
    // 所以我们用命令行参数接收 我们服务端的IP和port
    if (argc != 3)
    {
        usage(argv[0]);
        exit(1);
    }
    // 1.创建套接字  我们要在网络进行通信，是不是就要进行向下也就是传输层交付，传输层在操作系统，所以网络通信操作系统必须要给我们提供网络的系统调用接口
    //   也就是 socket系统调用！
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0)
    {
        logMessage(FATAL, "create socket error %s", strerror(errno));
        exit(1);
    }
    serverport = htons(atoi(argv[2]));
    serverip = argv[1];

    // 多线程
    std::unique_ptr<Thread> sender(new Thread(1, udpSend, (void *)&sock));
    std::unique_ptr<Thread> recver(new Thread(1, udpRecv, (void *)&sock));

    sender->start();
    recver->start();

    sender->join();
    recver->join();
    // 那我们要不要绑定端口呢？我们不用自己绑定端口！后面写完代码我们再谈！

    // while(true)
    // {
    //     //2.发送数据    sendto
    //     std::string str;
    //     //给服务器发消息，得知道服务器的IP和端口，所幸我们在命令行参数已经获取了
    //     struct sockaddr_in sv_data;
    //     memset(&sv_data,0,sizeof(sv_data));
    //     sv_data.sin_addr.s_addr = inet_addr(argv[1]);
    //     sv_data.sin_family= AF_INET;
    //     sv_data.sin_port = htons(atoi(argv[2]));
    //     std::cout << "请输入要发送的消息:";
    //     getline(std::cin,str);

    //     ssize_t ret = sendto(sock,str.c_str(),str.size(),0,(struct sockaddr*)&sv_data,sizeof(sv_data));
    //     if(ret < 0)
    //     {
    //         std::cout << "send error" << std::endl;
    //     }
    //     //开始读取服务器给我们返回的数据, 并且服务端的IP和端口号已经被设置进了sv_data
    //     char buffer[1024];
    //     socklen_t len = sizeof(sv_data);
    //     ssize_t s = recvfrom(sock,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&sv_data,&len);
    //     if(s >= 0)
    //     {
    //         buffer[s] = 0;
    //         std::cout << "服务器返回数据:" << buffer <<std::endl;
    //     }
    // }
    close(sock);

    return 0;
}